/*Generated from LLDB dump.*/
@Horky.Chen, 2013 * /
/ * * Copyright�2010 Apple Inc.All rights reserved. * /

const ReaderMinimumScore = 1600;
const ReaderMinimumAdvantage = 15;
const ArticleMinimumScoreDensity = 4.25;
var BlacklistedHostsAllowedPathPrefixesMap = {};
BlacklistedHostsAllowedPathPrefixesMap["www.apple.com"] = ["/pr/"];
const CandidateMinimumWidth = 280;
const CandidateMinimumHeight = 295;
const CandidateMinimumArea = 170000;
const CandidateMaximumTop = 1300;
const CandidateMinimumWidthPortionForIndicatorElements = 0.5;
const CandidateMinumumListItemLineCount = 4;
const CandidateTagNamesToIgnore = {
    "A": 1,
    "BODY": 1,
    "EMBED": 1,
    "FORM": 1,
    "HTML": 1,
    "IFRAME": 1,
    "OBJECT": 1,
    "OPTION": 1,
    "SCRIPT": 1,
    "STYLE": 1,
    "svg": 1
};
const CandidateTagNamesToIgnoreDescendantsOf = {
    "DD": 1,
    "DT": 1,
    "LI": 1,
    "OL": 1,
    "UL": 1
};

function shouldIgnoreElementBySelfOrAncestorTagName(element) {
    if (CandidateTagNamesToIgnore[element.tagName]) return true;
    for (var ancestor = element; ancestor; ancestor = ancestor.parentNode)
        if (CandidateTagNamesToIgnoreDescendantsOf[ancestor.tagName]) return true;
    return false;
}
const PrependedArticleCandidateMinimumHeight = 50;
const AppendedArticleCandidateMinimumHeight = 200;
const AppendedArticleCandidateMaximumVerticalDistanceFromArticle = 150;
const StylisticClassNames = {
    "justfy": 1,
    "justify": 1,
    "left": 1,
    "right": 1,
    "small": 1
};
const CommentRegEx = /comment | meta | footer | footnote /;
const CommentMatchPenalty = 0.5;
const ArticleRegEx = /(?:(?:^|\\s)(?:post|hentry|entry[-]?(?:content|text|body)?|article[-]?(?:content|text|body)?)(?:\\s|$))/;
const ArticleMatchBonus = 0.5;
const DensityExcludedElementSelector = "#disqus_thread, #comments, .userComments";
const AttributesToRemoveRegEx = /^on|^id$|^class$|^style$/;
const PositiveRegEx = /article|body|content|entry|hentry|page|pagination|post|text/i;
const NegativeRegEx = /breadcrumb|combx|comment|contact|disqus|foot|footer|footnote|link|media|meta|mod-conversations|promo|related|scroll|share|shoutbox|sidebar|social|sponsor|tags|toolbox|widget/i;
const MinimumAverageDistanceBetweenHRElements = 400;
const MinimumAverageDistanceBetweenHeaderElements = 400;
const PortionOfCandidateHeightToIgnoreForHeaderCheck = 0.1;
const ScoreMultiplierForChineseJapaneseKorean = 3;
const MinimumContentImageHeight = 200;
const MinimumContentImageWidthToArticleWidthRatio = 0.5;
const MaximumContentImageAreaToArticleAreaRatio = 0.2;
const LinkContinueMatchRegEx = /continue/gi;
const LinkNextMatchRegEx = /next/gi;
const LinkPageMatchRegEx = /page/gi;
const LinkListItemBonus = 5;
const LinkPageMatchBonus = 10;
const LinkNextMatchBonus = 15;
const LinkContinueMatchBonus = 15;
const LinkNextOrdinalValueBase = 3;
const LinkMismatchValueBase = 2;
const LinkMatchWeight = 200;
const LinkMaxVerticalDistanceFromArticle = 200;
const LinkVerticalDistanceFromArticleWeight = 150;
const LinkCandidateXPathQuery = "descendant-or-self::*[(not(@id) or (@id!='disqus_thread' and @id!='comments')) and (not(@class) or @class!='userComments')]/a";
const LinkDateRegex = /\D(?:\d\d(?:\d\d)?[\-\/](?:10|11|12|0?[1-9])[\-\/](?:30|31|[12][0-9]|0?[1-9])|\d\d(?:\d\d)?\/(?:10|11|12|0[1-9])|(?:10|11|12|0?[1-9])\-(?:30|31|[12][0-9]|0?[1-9])\-\d\d(?:\d\d)?|(?:30|31|[12][0-9]|0?[1-9])\-(?:10|11|12|0?[1-9])\-\d\d(?:\d\d)?)\D/;
const LinkURLSearchParameterKeyMatchRegex = /(page|^p$|^pg$)/i;
const LinkURLPageSlashNumberMatchRegex = /\/.*page.*\/\d+/i;
const LinkURLSlashDigitEndMatchRegex = /\/\d+\/?$/;
const LinkURLArchiveSlashDigitEndMatchRegex = /archives?\/\d+\/?$/;
const LinkURLBadSearchParameterKeyMatchRegex = /feed/;
const LinkURLSemanticMatchBonus = 100;
const LinkMinimumURLSimilarityRatio = 0.75;
const HeaderMinimumDistanceFromArticleTop = 200;
const HeaderLevenshteinDistanceToLengthRatio = 0.75;
const FloatMinimumHeight = 130;
const ImageSizeTiny = 32;
const ImageWidthToParentWidthRatio = .5;
const AnchorImageMinimumWidth = 100;
const AnchorImageMinimumHeight = 100;
const BaseFontSize = 16;
const BaseLineHeightRatio = 1.125;
const MaximumExactIntegralValue = 9007199254740992;
const TitleCandidateDepthScoreMultiplier = 0.1;
const DocumentPositionDisconnected = 0x01;
const DocumentPositionPreceding = 0x02;
const DocumentPositionFollowing = 0x04;
const DocumentPositionContains = 0x08;
const DocumentPositionContainedBy = 0x10;

function characterNeedsScoreMultiplier(character) {
    if (!character || character.length == 0) return false;
    var characterCode = character.charCodeAt(0);
    if (characterCode > 11904 && characterCode < 12031) return true;
    if (characterCode > 12352 && characterCode < 12543) return true;
    if (characterCode > 12736 && characterCode < 19903) return true;
    if (characterCode > 19968 && characterCode < 40959) return true;
    if (characterCode > 44032 && characterCode < 55215) return true;
    if (characterCode > 63744 && characterCode < 64255) return true;
    if (characterCode > 65072 && characterCode < 65103) return true;
    if (characterCode > 131072 && characterCode < 173791) return true;
    if (characterCode > 194560 && characterCode < 195103) return true;
    return false;
}

function domDistance(elementA, elementB, distanceCap) {
    var ancestorsA = [];
    var node = elementA;
    while (node) {
        ancestorsA.unshift(node);
        node = node.parentNode;
    }
    var ancestorsB = [];
    node = elementB;
    while (node) {
        ancestorsB.unshift(node);
        node = node.parentNode;
    }
    var shallowerDepth = Math.min(ancestorsA.length, ancestorsB.length);
    var domDistance = Math.abs(ancestorsA.length - ancestorsB.length);
    for (var i = shallowerDepth; i >= 0; i--) {
        if (ancestorsA[i] === ancestorsB[i]) break;
        domDistance += 2;
        if (distanceCap && domDistance >= distanceCap) return distanceCap;
    }
    return domDistance;
}

function fontSizeFromComputedStyle(style, fallbackSize) {
    var fontSize = parseInt(style.fontSize);
    if (isNaN(fontSize)) fontSize = fallbackSize ? fallbackSize : BaseFontSize;
    return fontSize;
}

function contentTextStyleForNode(contentDocument, node, searchInReverse) {
    function getComputedStyleIfNodeIsBodyText(textNode) {
        if (isNodeWhitespace(textNode)) return null;
        var style = getComputedStyle(textNode.parentNode);
        if (style.float !== "none") return null;
        return style;
    }
    var nonHeaderTextXPathQuery = "descendant::text()[not(parent::h1) and not(parent::h2) and not(parent::h3) and not(parent::h4) and not(parent::h5) and not(parent::h6)]";
    var articleTextNodes = contentDocument.evaluate(nonHeaderTextXPathQuery, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    if (searchInReverse) {
        for (var nodeIndex = articleTextNodes.snapshotLength - 1; nodeIndex >= 0; nodeIndex--) {
            var style = getComputedStyleIfNodeIsBodyText(articleTextNodes.snapshotItem(nodeIndex));
            if (style) return style;
        }
    } else {
        for (var nodeIndex = 0; nodeIndex < articleTextNodes.snapshotLength; nodeIndex++) {
            var style = getComputedStyleIfNodeIsBodyText(articleTextNodes.snapshotItem(nodeIndex));
            if (style) return style;
        }
    }
    return null;
}

function isNodeWhitespace(node) {
    if (!node || node.nodeType !== Node.TEXT_NODE) return false;
    return !/\S/.test(node.data);
}

function removeWhitespace(string) {
    return string.replace(/\s+/g, '');
}

function isElementNode(node) {
    if (node && node.nodeType === Node.ELEMENT_NODE) return true;
    return false;
}

function isElementVisible(element) {
    var style = getComputedStyle(element);
    if (style.visibility !== "visible" || style.display === "none") return false;
    if (!cachedElementBoundingRect(element).height) return false;
    return true;
}

function elementDepth(element) {
    var depth = 0;
    while (element) {
        element = element.parentElement;
        depth++;
    }
    return depth;
}

function elementHasAncestorWithTagName(element, tagName) {
    var node = element;
    while (node.parentNode) {
        node = node.parentNode;
        if (node.tagName === tagName) return true;
    }
    return false;
}

function cachedElementBoundingRect(element) {
    if (element._cachedElementBoundingRect) return element._cachedElementBoundingRect;
    var rect = element.getBoundingClientRect();
    ReaderArticleFinderJS._elementsWithCachedBoundingRects.push(element);
    if (!ReaderArticleFinderJS._cachedScrollY && !ReaderArticleFinderJS._cachedScrollY) {
        element._cachedElementBoundingRect = rect;
        return element._cachedElementBoundingRect;
    }
    element._cachedElementBoundingRect = {
    top: rect.top + ReaderArticleFinderJS._cachedScrollY,
    right: rect.right - ReaderArticleFinderJS._cachedScrollX,
    bottom: rect.bottom - ReaderArticleFinderJS._cachedScrollY,
    left: rect.left + ReaderArticleFinderJS._cachedScrollX,
    width: rect.width,
    height: rect.height
    };
    return element._cachedElementBoundingRect;
}

function clearCachedElementBoundingRects() {
    var elementsWithRects = ReaderArticleFinderJS._elementsWithCachedBoundingRects;
    var elementCount = elementsWithRects.length;
    for (var i = 0; i < elementCount; i++)
        elementsWithRects[i]._cachedElementBoundingRect = null;
    ReaderArticleFinderJS._elementsWithCachedBoundingRects = [];
}

function innerTextOrTextContent(element) {
    var text = element.innerText;
    if (!text) text = element.textContent;
    return text;
}

function levenshteinDistance(s, t) {
    var m = s.length;
    var n = t.length;
    var d = new Array(m + 1);
    for (var i = 0; i < m + 1; i++) {
        d[i] = new Array(n + 1);
        d[i][0] = i;
    }
    for (var j = 0; j < n + 1; j++)
        d[0][j] = j;
    for (var j = 1; j < n + 1; j++) {
        for (var i = 1; i < m + 1; i++) {
            if (s[i - 1] === t[j - 1]) d[i][j] = d[i - 1][j - 1];
            else {
                var deletion = d[i - 1][j] + 1;
                var insertion = d[i][j - 1] + 1;
                var substitution = d[i - 1][j - 1] + 1;
                d[i][j] = Math.min(deletion, insertion, substitution);
            }
        }
    }
    return d[m][n];
}

function stringSimilarity(s, t) {
    var maxLength = Math.max(s.length, t.length);
    return maxLength ? (maxLength - levenshteinDistance(s, t)) / maxLength : 0;
}
CandidateElement = function (element, contentDocument) {
    this.element = element
    this.contentDocument = contentDocument;
    this.textNodes = this.usableTextNodesInElement(this.element);
    this.rawScore = this.calculateRawScore();
    this.regExBonusMultiplier = this.calculateRegExBonus();
    this.languageScoreMultiplier = 0;
    this.depthInDocument = 0;
}
CandidateElement.extraArticleCandidateIfElementIsViable = function extraArticleCandidateIfElementIsViable(element, selectedArticle, contentDocument, isPrepended) {
    const InlineTextContainerTagNames = "a, b, strong, i, em, u, span";
    var documentRect = cachedElementBoundingRect(element);
    var selectedArticleRect = cachedElementBoundingRect(selectedArticle.element);
    if ((isPrepended && documentRect.height < PrependedArticleCandidateMinimumHeight) || (!isPrepended && documentRect.height < AppendedArticleCandidateMinimumHeight)) {
        if (element.childElementCount && element.querySelectorAll("*").length != element.querySelectorAll(InlineTextContainerTagNames).length) return null;
    }
    if (isPrepended) {
        if (documentRect.bottom > selectedArticleRect.top) return null;
    } else {
        if (documentRect.top < selectedArticleRect.bottom) return null;
    }
    if (!isPrepended) {
        var distanceFromArticle = documentRect.top - selectedArticleRect.bottom;
        console.assert(distanceFromArticle > 0, "An appended article node must be below the article");
        if (distanceFromArticle > AppendedArticleCandidateMaximumVerticalDistanceFromArticle) return null;
    }
    var maxDelta = 0.1 * selectedArticleRect.width;
    if (Math.abs(documentRect.left - selectedArticleRect.left) > maxDelta || Math.abs(documentRect.right - selectedArticle.right) > maxDelta) return null;
    var candidate = new CandidateElement(element, contentDocument);
    candidate.isPrepended = isPrepended;
    return candidate;
}
CandidateElement.candidateIfElementIsViable = function candidateIfElementIsViable(element, contentDocument, isForSimilarClass) {
    var documentRect = cachedElementBoundingRect(element);
    if (isForSimilarClass) return new CandidateElement(element, contentDocument);
    if (documentRect.width < CandidateMinimumWidth || documentRect.height < CandidateMinimumHeight) return null;
    if (documentRect.width * documentRect.height < CandidateMinimumArea) return null;
    if (documentRect.top > CandidateMaximumTop) return null;
    if (CandidateElement.candidateElementAdjustedHeight(element) < CandidateMinimumHeight) return null;
    return new CandidateElement(element, contentDocument);
}
CandidateElement.candidateElementAdjustedHeight = function candidateElementAdjustedHeight(element) {
    var documentRect = cachedElementBoundingRect(element);
    var adjustedHeight = documentRect.height;
    var indicatorElements = element.querySelectorAll("form");
    for (var i = 0; i < indicatorElements.length; i++) {
        var indicatorElement = indicatorElements[i];
        var indicatorRect = cachedElementBoundingRect(indicatorElement);
        if (indicatorRect.width > documentRect.width * CandidateMinimumWidthPortionForIndicatorElements) adjustedHeight -= indicatorRect.height;
    }
    var listContainers = element.querySelectorAll("ol, ul");
    var listContainersCount = listContainers.length;
    var lastListContainerSubstracted = null;
    for (var i = 0; i < listContainersCount; i++) {
        var listContainer = listContainers[i];
        if (lastListContainerSubstracted && lastListContainerSubstracted.compareDocumentPosition(listContainer) & DocumentPositionContainedBy) continue;
        var listItems = listContainer.querySelectorAll("li");
        var listItemCount = listItems.length;
        var listRect = cachedElementBoundingRect(listContainer);
        if (!listItemCount) {
            adjustedHeight -= listRect.height;
            continue;
        }
        var averageListItemHeight = listRect.height / listItemCount;
        var firstListItemStyle = getComputedStyle(listItems[0]);
        var listLineHeight = parseInt(firstListItemStyle.lineHeight);
        if (isNaN(listLineHeight)) {
            var listFontSize = fontSizeFromComputedStyle(firstListItemStyle);
            listLineHeight = listFontSize * BaseLineHeightRatio;
        }
        if (listRect.width > documentRect.width * CandidateMinimumWidthPortionForIndicatorElements && ((averageListItemHeight / listLineHeight) < CandidateMinumumListItemLineCount)) {
            adjustedHeight -= listRect.height;
            lastListContainerSubstracted = listContainer;
        }
    }
    return adjustedHeight;
}
CandidateElement.prototype = {
calculateRawScore: function calculateRawScore() {
    var score = 0;
    var textNodes = this.textNodes;
    for (var i = 0; i < textNodes.length; i++)
        score += this.rawScoreForTextNode(textNodes[i]);
    return score;
},
calculateRegExBonus: function calculateRegExBonus() {
    var regExBonusMultiplier = 1;
    for (var currentElement = this.element; currentElement; currentElement = currentElement.parentElement) {
        var currentElementId = currentElement.getAttribute("id");
        if (currentElementId) {
            if (ArticleRegEx.test(currentElementId)) regExBonusMultiplier += ArticleMatchBonus;
            if (CommentRegEx.test(currentElementId)) regExBonusMultiplier -= CommentMatchPenalty;
        }
        var currentElementClassName = currentElement.className;
        if (currentElementClassName && typeof currentElementClassName === "string") {
            if (ArticleRegEx.test(currentElementClassName)) regExBonusMultiplier += ArticleMatchBonus;
            if (CommentRegEx.test(currentElementClassName)) regExBonusMultiplier -= CommentMatchPenalty;
        }
    }
    return regExBonusMultiplier;
},
calculateLanguageScoreMultiplier: function calculateLanguageScoreMultiplier() {
    if (this.languageScoreMultiplier != 0) return;
    if (this.textNodes && this.textNodes.length > 0) {
        var numCharactersThatNeedMultiplier = 0;
        var textString = this.textNodes[0].nodeValue.trim();
        var length = Math.min(textString.length, 10);
        for (var i = 0; i < length; i++) {
            if (characterNeedsScoreMultiplier(textString[i])) numCharactersThatNeedMultiplier++;
        }
        if (numCharactersThatNeedMultiplier >= length / 2) {
            this.languageScoreMultiplier = ScoreMultiplierForChineseJapaneseKorean;
            return;
        }
    }
    this.languageScoreMultiplier = 1;
},
depth: function depth() {
    if (!this.depthInDocument) this.depthInDocument = elementDepth(this.element);
    return this.depthInDocument;
},
finalScore: function finalScore() {
    this.calculateLanguageScoreMultiplier();
    return this.basicScore() * this.languageScoreMultiplier;
},
basicScore: function basicScore() {
    return this.rawScore * this.regExBonusMultiplier;
},
scoreDensity: function scoreDensity() {
    var ignoredArea = 0;
    var ignoredElement = this.element.querySelector(DensityExcludedElementSelector);
    if (ignoredElement) ignoredArea = ignoredElement.clientWidth * ignoredElement.clientHeight;
    var articleArea = cachedElementBoundingRect(this.element).width * cachedElementBoundingRect(this.element).height;
    var maximumImageArea = articleArea * MaximumContentImageAreaToArticleAreaRatio;
    var imageMinimumWidth = cachedElementBoundingRect(this.element).width * MinimumContentImageWidthToArticleWidthRatio;
    var imageElements = this.element.querySelectorAll("img");
    var imageCount = imageElements.length;
    for (var i = 0; i < imageCount; i++) {
        var imageRect = cachedElementBoundingRect(imageElements[i]);
        if (imageRect.width >= imageMinimumWidth && imageRect.height > MinimumContentImageHeight) {
            var imageArea = imageRect.width * imageRect.height;
            if (imageArea < maximumImageArea) ignoredArea += imageArea;
        }
    }
    var score = this.basicScore();
    var area = articleArea - ignoredArea;
    var numberOfTextNodes = this.textNodes.length;
    var numberOfCountedTextNodes = 0;
    var sumOfFontSizes = 0;
    for (var i = 0; i < numberOfTextNodes; i++) {
        var parentNode = this.textNodes[i].parentNode;
        console.assert(parentNode, "parentNode of this.textNodes[i] cannot be nil");
        if (parentNode) {
            sumOfFontSizes += fontSizeFromComputedStyle(getComputedStyle(parentNode));
            numberOfCountedTextNodes++;
        }
    }
    var averageFontSize = BaseFontSize;
    if (numberOfCountedTextNodes) averageFontSize = sumOfFontSizes /= numberOfCountedTextNodes;
    this.calculateLanguageScoreMultiplier();
    return (score / area * 1000) * (averageFontSize / BaseFontSize) * this.languageScoreMultiplier;
},
usableTextNodesInElement: function usableTextNodesInElement(element) {
    var textNodes = [];
    if (!element) return textNodes;
    const tagNamesToIgnore = {
        "A": 1,
        "DD": 1,
        "DT": 1,
        "NOSCRIPT": 1,
        "OL": 1,
        "OPTION": 1,
        "PRE": 1,
        "SCRIPT": 1,
        "STYLE": 1,
        "TD": 1,
        "UL": 1
    };
    var xPathQuery = "text()|*/text()|*/a/text()|*/li/text()|*/span/text()|*/em/text()|*/i/text()|*/strong/text()|*/b/text()|*/font/text()|blockquote/*/text()|div[count(./p)=count(./*)]/p/text()";
    var xPathResults = this.contentDocument.evaluate(xPathQuery, element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0; i < xPathResults.snapshotLength; i++) {
        var textNode = xPathResults.snapshotItem(i);
        if (tagNamesToIgnore[textNode.parentNode.tagName]) continue;
        if (isNodeWhitespace(textNode)) continue;
        textNodes.push(textNode);
    }
    return textNodes;
},
addTextNodesFromCandidateElement: function addTextNodesFromCandidateElement(otherCandidateElement) {
    for (var j = 0; j < this.textNodes.length; j++)
        this.textNodes[j].alreadyCounted = true;
    var otherCandidateElementTextNodes = otherCandidateElement.textNodes;
    for (var j = 0; j < otherCandidateElementTextNodes.length; j++) {
        if (!otherCandidateElementTextNodes[j].alreadyCounted) this.textNodes.push(otherCandidateElementTextNodes[j]);
    }
    for (var j = 0; j < this.textNodes.length; j++)
        this.textNodes[j].alreadyCounted = null;
    this.rawScore = this.calculateRawScore();
},
rawScoreForTextNode: function rawScoreForTextNode(textNode) {
    const TextNodeMinimumLength = 20;
    const TextNodeLengthPower = 1.25;
    if (!textNode) return 0;
    var length = textNode.length;
    if (length < TextNodeMinimumLength) return 0;
    var ancestor = textNode.parentNode;
    if (!isElementVisible(ancestor)) return 0;
    var multiplier = 1;
    while (ancestor && ancestor != this.element) {
        multiplier -= 0.1;
        ancestor = ancestor.parentNode;
    }
    return Math.pow(length * multiplier, TextNodeLengthPower);
},
shouldDisqualifyDueToScoreDensity: function shouldDisqualifyDueToScoreDensity() {
    if (this.scoreDensity() < ArticleMinimumScoreDensity) return true;
    return false;
},
shouldDisqualifyDueToHorizontalRuleDensity: function shouldDisqualifyDueToHorizontalRuleDensity() {
    var horizontalRules = this.element.querySelectorAll("hr");
    var numberOfHRs = horizontalRules.length;
    var numberOfHRsToCount = 0;
    var elementRect = cachedElementBoundingRect(this.element);
    var minimumWidthToCount = elementRect.width * 0.70;
    for (var i = 0; i < numberOfHRs; i++) {
        if (horizontalRules[i].clientWidth > minimumWidthToCount) numberOfHRsToCount++;
    }
    if (numberOfHRsToCount) {
        var averageDistanceBetweenHRs = elementRect.height / numberOfHRsToCount;
        if (averageDistanceBetweenHRs < MinimumAverageDistanceBetweenHRElements) return true;
    }
    return false;
},
shouldDisqualifyDueToHeaderDensity: function shouldDisqualifyDueToHeaderDensity() {
    var headerLinksXPathQuery = "(h1|h2|h3|h4|h5|h6|*/h1|*/h2|*/h3|*/h4|*/h5|*/h6)[a]";
    var headerLinkResults = this.contentDocument.evaluate(headerLinksXPathQuery, this.element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    if (headerLinkResults.snapshotLength > 2) {
        var numberOfHeadersToCount = 0;
        var elementRect = cachedElementBoundingRect(this.element);
        var topBottomIgnoreDistance = elementRect.height * PortionOfCandidateHeightToIgnoreForHeaderCheck;
        for (var i = 0; i < headerLinkResults.snapshotLength; i++) {
            var header = headerLinkResults.snapshotItem(i);
            var headerRect = cachedElementBoundingRect(header);
            if (headerRect.top - elementRect.top > topBottomIgnoreDistance && elementRect.bottom - headerRect.bottom > topBottomIgnoreDistance) numberOfHeadersToCount++;
        }
        var averageDistanceBetweenHeaders = elementRect.height / numberOfHeadersToCount;
        if (averageDistanceBetweenHeaders < MinimumAverageDistanceBetweenHeaderElements) return true;
    }
    return false;
},
shouldDisqualifyDueToSimilarElements: function shouldDisqualifyDueToSimilarElements(candidateElements) {
    var baseElement = this.element;
    var candidateClass = baseElement.getAttribute("class");
    if (!candidateClass) {
        baseElement = baseElement.parentElement;
        if (baseElement) {
            candidateClass = baseElement.getAttribute("class");
            if (!candidateClass) {
                baseElement = baseElement.parentElement;
                if (baseElement) candidateClass = baseElement.getAttribute("class");
            }
        }
    }
    if (candidateClass) {
        if (candidateElements === undefined) candidateElements = [];
        for (var i = 0; i < candidateElements.length; i++)
            candidateElements[i].element.candidateElement = candidateElements[i];
        var elementsOfSameClass;
        try {
            var classNames = candidateClass.split(" ");
            var classQuery = "";
            for (var j = 0; j < classNames.length; j++) {
                if (classNames[j].length) classQuery += "." + classNames[j];
            }
            elementsOfSameClass = this.contentDocument.querySelectorAll(classQuery);
        } catch (exception) {
            elementsOfSameClass = [];
        }
        var skippedPossiblePrependCandidate = false;
        var baseElementDepth = elementDepth(baseElement);
        for (var i = 0; i < elementsOfSameClass.length; i++) {
            var element = elementsOfSameClass[i];
            if (element == baseElement) continue;
            if (element.parentElement == baseElement || baseElement.parentElement == element) continue;
            if (!isElementVisible(element)) continue;
            var candidate = element.candidateElement;
            if (!candidate) {
                candidate = CandidateElement.candidateIfElementIsViable(element, this.contentDocument, true);
                if (!candidate) continue;
            }
            if (candidate.basicScore() * ReaderMinimumAdvantage > this.basicScore()) {
                if (!skippedPossiblePrependCandidate && cachedElementBoundingRect(element).bottom < cachedElementBoundingRect(this.element).top) {
                    skippedPossiblePrependCandidate = true;
                    continue;
                }
                if (element.previousElementSibling != null && baseElement.previousElementSibling != null && element.previousElementSibling.className == baseElement.previousElementSibling.className) return true;
                if (element.nextElementSibling != null && baseElement.nextElementSibling != null && element.nextElementSibling.className == baseElement.nextElementSibling.className) return true;
                if (elementDepth(element) == baseElementDepth) {
                    while (element.parentElement != null && baseElement.parentElement != null) {
                        if (element.parentElement == baseElement.parentElement) break;
                        element = element.parentElement;
                        baseElement = baseElement.parentElement;
                    }
                }
                while (baseElement.childElementCount <= 1) {
                    if (!baseElement.childElementCount || !element.childElementCount) return false;
                    if (element.childElementCount > 1) return false;
                    if (baseElement.firstElementChild.tagName !== element.firstElementChild.tagName) return false;
                    baseElement = baseElement.firstElementChild;
                    element = element.firstElementChild;
                }
                if (element.childElementCount <= 1) return false;
                var elementHeader = element.firstElementChild;
                var elementFooter = element.lastElementChild;
                var baseElementHeader = baseElement.firstElementChild;
                var baseElementFooter = baseElement.lastElementChild;
                if (elementHeader.tagName !== baseElementHeader.tagName) return false;
                if (elementFooter.tagName !== baseElementFooter.tagName) return false;
                var headerClass = elementHeader.className;
                var footerClass = elementFooter.className;
                var baseHeaderClass = baseElementHeader.className;
                var baseFooterClass = elementFooter.className;
                var acceptableNumberOfElementsWithClassName = (baseFooterClass == baseHeaderClass) ? 2 : 1;
                if (headerClass.length || baseHeaderClass.length) {
                    if (!headerClass.length || !baseHeaderClass.length) return false;
                    if (headerClass == baseHeaderClass) {
                        if (baseElement.querySelectorAll("." + baseHeaderClass.replace(/\s+/, ".")).length <= acceptableNumberOfElementsWithClassName) return true;
                    }
                }
                if (footerClass.length || baseFooterClass.length) {
                    if (!footerClass.length || !baseFooterClass.length) return false;
                    if (footerClass == baseFooterClass && baseElement.querySelectorAll("." + baseFooterClass.replace(/\s+/, ".")).length <= acceptableNumberOfElementsWithClassName) return true;
                }
                var baseHeaderHeight = baseElementHeader.clientHeight;
                var baseFooterHeight = baseElementFooter.clientHeight;
                if (!baseHeaderHeight || !elementHeader.clientHeight) return false;
                if (!baseFooterHeight || !elementFooter.clientHeight) return false;
                if (baseHeaderHeight == elementHeader.clientHeight || baseFooterHeight == elementFooter.clientHeight) return true;
                return false;
            }
        }
        for (var i = 0; i < candidateElements.length; i++)
            candidateElements[i].element.candidateElement = null;
    }
    return false;
}
}
String.prototype.lastInteger = function lastInteger() {
    const DecimalRunsRegEx = /[0-9]+/g;
    var decimalRuns = this.match(DecimalRunsRegEx);
    if (decimalRuns) return parseInt(decimalRuns[decimalRuns.length - 1]);
    return NaN;
}
String.prototype.trim = function trim() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
}
String.prototype.escapeCharacters = function (chars) {
    var foundChar = false;
    for (var i = 0; i < chars.length; ++i) {
        if (this.indexOf(chars.charAt(i)) !== -1) {
            foundChar = true;
            break;
        }
    }
    if (!foundChar) return this;
    var result = "";
    for (var i = 0; i < this.length; ++i) {
        if (chars.indexOf(this.charAt(i)) !== -1) result += "\\";
        result += this.charAt(i);
    }
    return result;
}
String.prototype.escapeForRegExp = function () {
    return this.escapeCharacters("^[]{}()\\.$*+?|");
}
ReaderArticleFinder = function (contentDocument) {
    this.contentDocument = contentDocument;
    this.didSearchForArticleNode = false;
    this.article = null;
    this.didSearchForExtraArticleNode = false;
    this.extraArticle = null;
    this.leadingImage = null;
    this._cachedScrollY = 0;
    this._cachedScrollX = 0;
    this._elementsWithCachedBoundingRects = [];
    this._cachedContentTextStyle = null;
    this.pageNumber = 1;
    this.prefixWithDateForNextPageURL = null;
}
ReaderArticleFinder.prototype = {
isReaderModeAvailable: function isReaderModeAvailable() {
    this.cacheWindowScrollPosition();
    var article = this.articleNode();
    return article != null;
},
prepareToTransitionToReader: function prepareToTransitionToReader() {
    clearCachedElementBoundingRects();
    this.cacheWindowScrollPosition();
    this.nextPageURL();
    this.articleIsLTR();
    this.adoptableArticle();
},
nextPageURL: function nextPageURL() {
    if (this._nextPageURL === undefined) {
        var nextPageURLString = this.nextPageURLString();
        if (nextPageURLString) {
            nextPageURLString = ReaderArticleFinderJSController.substituteURLForNextPageURL(nextPageURLString);
        }
        this._nextPageURL = nextPageURLString;
    }
    return this._nextPageURL;
},
classNameIsSignificantInRouteComputation: function classNameIsSignificantInRouteComputation(className) {
    if (!className) return false;
    return !(className.toLowerCase() in StylisticClassNames);
},
shouldIgnoreInRouteComputation: function shouldIgnoreInRouteComputation(element) {
    if (element.tagName === "SCRIPT" || element.tagName === "LINK" || element.tagName === "STYLE") return true;
    if (element.tagName !== "TR") return false;
    if (element.offsetHeight) return false;
    return true;
},
routeToArticleNode: function routeToArticleNode() {
    var hint = [];
    var currentElement = this.articleNode();
    while (currentElement) {
        var step = {};
        step.tagName = currentElement.tagName;
        if (currentElement.id) step.id = currentElement.id;
        if (this.classNameIsSignificantInRouteComputation(currentElement.className)) step.className = currentElement.className;
        step.index = 1;
        for (var sibling = currentElement.previousElementSibling; sibling; sibling = sibling.previousElementSibling) {
            if (!this.shouldIgnoreInRouteComputation(sibling)) step.index++;
        }
        hint.unshift(step);
        currentElement = currentElement.parentElement;
    }
    return hint;
},
articleNode: function articleNode() {
    if (!this.didSearchForArticleNode) {
        this.article = this.findArticle();
        this.didSearchForArticleNode = true;
        if (this.article) this.articleIsLTR();
    }
    return this.article ? this.article.element : null;
},
extraArticleNode: function extraArticleNode() {
    if (!this.didSearchForArticleNode) this.articleNode();
    if (!this.didSearchForExtraArticleNode) {
        this.extraArticle = this.findExtraArticle();
        this.didSearchForExtraArticleNode = true;
    }
    return this.extraArticle ? this.extraArticle.element : null;
},
cacheWindowScrollPosition: function cacheWindowScrollPosition() {
    this._cachedScrollY = window.scrollY;
    this._cachedScrollX = window.scrollX;
},
contentTextStyle: function contentTextStyle() {
    if (this._cachedContentTextStyle) return this._cachedContentTextStyle;
    this._cachedContentTextStyle = contentTextStyleForNode(this.contentDocument, this.articleNode(), false);
    if (!this._cachedContentTextStyle) this._cachedContentTextStyle = getComputedStyle(this.articleNode());
    return this._cachedContentTextStyle;
},
commaCountIsLessThan: function commaCountIsLessThan(node, limit) {
    var count = 0;
    var textContent = node.textContent;
    var i = -1;
    while (count < limit && (i = textContent.indexOf(',', i + 1)) >= 0)
        count++;
    return count < limit;
},
calculateLinkDensity: function calculateLinkDensity(element) {
    var textLength = removeWhitespace(element.textContent).length;
    if (!textLength) return 0;
    var links = element.querySelectorAll("a");
    var linkCharacterCount = 0;
    for (var i = 0; i < links.length; i++)
        linkCharacterCount += removeWhitespace(links[i].textContent).length;
    return linkCharacterCount / textLength;
},
shouldPruneElement: function shouldPruneElement(element, originalElement) {
    const MaxInputToParagraphRatio = 0.33;
    const MaxPositiveWeightLinkDensity = 0.5;
    const MaxStandardLinkDensity = 0.2;
    const MinimumTextLength = 25;
    const MinimumAverageImageArea = 200 * 200;
    if (!element.parentElement) return false;
    if (element.tagName !== "OBJECT" && element.tagName !== "EMBED" && element.tagName !== "CANVAS") {
        var hasElementOrTextNodeChild = false;
        for (var i = 0; i < element.childNodes.length; i++) {
            var node = element.childNodes[i];
            var nodeType = node.nodeType;
            if (nodeType === Node.ELEMENT_NODE || (nodeType === Node.TEXT_NODE && !isNodeWhitespace(node))) {
                hasElementOrTextNodeChild = true;
                break;
            }
        }
        if (!hasElementOrTextNodeChild) return true;
    }
    if (element.tagName === "CANVAS") return element.parentNode.tagName === "CUFON";
    var classIdWeight = 0;
    if (originalElement) {
        if (PositiveRegEx.test(originalElement.className)) classIdWeight++;
        if (PositiveRegEx.test(originalElement.id)) classIdWeight++;
        if (NegativeRegEx.test(originalElement.className)) classIdWeight--;
        if (NegativeRegEx.test(originalElement.id)) classIdWeight--;
    }
    if (classIdWeight < 0) return true;
    if (element.tagName === "UL") {
        if (originalElement.querySelector("iframe") && originalElement.querySelector("script")) return true;
        return false;
    }
    if (element.tagName === "OBJECT") {
        const PlugInsToKeepRegEx = /youtube|vimeo|dailymotion/;
        var embedElement = element.querySelector("embed[src]");
        if (embedElement && PlugInsToKeepRegEx.test(embedElement.src)) return false;
        var dataAttribute = element.getAttribute("data");
        if (dataAttribute && PlugInsToKeepRegEx.test(dataAttribute)) return false;
        return true;
    }
    if (element.childElementCount === 1) {
        var childElement = element.firstElementChild;
        if (childElement.tagName === "A") return false;
        if (childElement.tagName === "SPAN" && childElement.className === "converted-anchor" && elementHasAncestorWithTagName(childElement, "TABLE")) return false;
    }
    var imageElements = element.querySelectorAll("img");
    var imageElementCount = imageElements.length;
    if (imageElementCount) {
        var averageImageArea = 0;
        for (var i = 0; i < imageElementCount; i++) {
            var originalImage = imageElements[i].originalElement;
            if (!isElementVisible(originalImage)) continue;
            var originalRect = cachedElementBoundingRect(originalImage);
            averageImageArea += (originalRect.width / imageElementCount) * (originalRect.height / imageElementCount);
        }
        if (averageImageArea > MinimumAverageImageArea) return false;
    }
    if (!this.commaCountIsLessThan(element, 10)) return false;
    var p = element.querySelectorAll("p").length;
    var br = element.querySelectorAll("br").length;
    var numParagraphs = p + Math.floor(br / 2);
    if (imageElementCount > numParagraphs) return true;
    if (element.querySelectorAll("li").length > numParagraphs) return true;
    if (element.querySelectorAll("input").length / numParagraphs > MaxInputToParagraphRatio) return true;
    if (element.textContent.length < MinimumTextLength && (imageElementCount != 1)) return true;
    if (element.querySelector("embed")) return true;
    var linkDensity = this.calculateLinkDensity(element);
    if (classIdWeight >= 1 && linkDensity > MaxPositiveWeightLinkDensity) return true;
    if (classIdWeight < 1 && linkDensity > MaxStandardLinkDensity) return true;
    if (element.tagName === "TABLE") {
        var textLength = removeWhitespace(element.innerText).length;
        var originalTextLength = removeWhitespace(originalElement.innerText).length;
        if (textLength <= (originalTextLength * 0.5)) return true;
    }
    return false;
},
wordCountIsLessThan: function wordCountIsLessThan(node, limit) {
    var count = 0;
    var textContent = node.textContent;
    var i = -1;
    while ((i = textContent.indexOf(' ', i + 1)) >= 0 && count < limit)
        count++;
    return count < limit;
},
leadingImageIsAppropriateWidth: function leadingImageIsAppropriateWidth(image) {
    if (!this.article || !image) return false;
    return image.getBoundingClientRect().width >= this.article.element.getBoundingClientRect().width;
},
newDivFromNode: function newDivFromNode(node) {
    var div = this.contentDocument.createElement("div");
    if (node) div.innerHTML = node.innerHTML;
    return div;
},
adoptableLeadingImage: function adoptableLeadingImage() {
    const LeadingImageMaximumContainerChildren = 5;
    const LeadingImageMinimumAbsoluteWidth = 600;
    const LeadingImageCreditRegex = /credit/;
    const LeadingImageCaptionRegex = /caption/;
    const LeadingImageAttributeToKeepRegex = /src|alt/;
    if (!this.article || !this.leadingImage || !this.leadingImageIsAppropriateWidth(this.leadingImage)) return null;
    var leadingImageContainer = this.leadingImage.parentNode;
    var originalCredit = null;
    var originalCaption = null;
    var numChildren = leadingImageContainer.children.length;
    if (leadingImageContainer.tagName === "DIV" && numChildren > 1 && numChildren < LeadingImageMaximumContainerChildren) {
        var texts = leadingImageContainer.cloneNode(true).querySelectorAll("p, div");
        for (var i = 0, length = texts.length; i < length; i++) {
            var text = texts[i];
            if (LeadingImageCreditRegex.test(text.className)) originalCredit = text.cloneNode(true);
            else if (LeadingImageCaptionRegex.test(text.className)) originalCaption = text.cloneNode(true);
        }
    }
    var image = this.leadingImage.cloneNode(false);
    var attributes = image.attributes;
    for (var i = 0; i < attributes.length; i++) {
        var attributeName = attributes[i].nodeName;
        if (!LeadingImageAttributeToKeepRegex.test(attributeName)) {
            image.removeAttribute(attributeName);
            i--;
        }
    }
    image.className = image.width >= LeadingImageMinimumAbsoluteWidth ? "full-width" : null;
    var container = this.contentDocument.createElement("div");
    container.className = "leading-image";
    container.appendChild(image);
    if (originalCredit) {
        var credit = this.newDivFromNode(originalCredit);
        credit.className = "credit";
        container.appendChild(credit);
    }
    if (originalCaption) {
        var caption = this.newDivFromNode(originalCaption);
        caption.className = "caption";
        container.appendChild(caption);
    }
    return container;
},
adoptableArticle: function adoptableArticle() {
    if (this._adoptableArticle !== undefined) {
        return this._adoptableArticle.cloneNode(true);
    }
    var rootElement = this.articleNode();
    this._adoptableArticle = rootElement ? rootElement.cloneNode(true) : null;
    if (!this._adoptableArticle) return this._adoptableArticle;
    this._adoptableArticle = this.cleanArticleNode(rootElement, this._adoptableArticle, false)
    var extraArticle = this.extraArticleNode();
    if (extraArticle) {
        var cleanedExtraNode = this.cleanArticleNode(extraArticle, extraArticle.cloneNode(true), true);
        if (cleanedExtraNode) {
            if (this.extraArticle.isPrepended) this._adoptableArticle.insertBefore(cleanedExtraNode, this._adoptableArticle.firstChild);
            else this._adoptableArticle.appendChild(cleanedExtraNode);
        }
    }
    this._articleTextContent = this._adoptableArticle.innerText;
    var leadingImage = this.adoptableLeadingImage();
    if (leadingImage) this._adoptableArticle.insertBefore(leadingImage, this._adoptableArticle.firstChild);
    return this._adoptableArticle;
},
elementPinToEdge: function elementPinToEdge(originalArticleNode) {
    const tagNamesDontAddChild = {
        "AREA": 1,
        "BR": 1,
        "CANVAS": 1,
        "EMBED": 1,
        "FRAME": 1,
        "HR": 1,
        "IMG": 1,
        "INPUT": 1
    };
    const kMinimumScrollForAddingPinElement = 120;
    if (window.scrollY < kMinimumScrollForAddingPinElement) return null;
    var articleRect = cachedElementBoundingRect(originalArticleNode);
    var element = originalArticleNode.ownerDocument.elementFromPoint((articleRect.left + articleRect.right) / 2, 0);
    if (element && element.tagName in tagNamesDontAddChild) element = element.parentElement;
    var parent = element;
    while (parent && parent != originalArticleNode) {
        parent = parent.parentNode;
    }
    if (parent == null) return null;
    return element;
},
cleanArticleNode: function cleanArticleNode(originalArticleNode, clonedArticleNode, allowedToReturnNull) {
    const tagNamesToAlwaysPrune = {
        "FORM": 1,
        "IFRAME": 1,
        "SCRIPT": 1,
        "STYLE": 1,
        "LINK": 1
    };
    const tagNamesToConsiderPruning = {
        "DIV": 1,
        "TABLE": 1,
        "OBJECT": 1,
        "UL": 1,
        "CANVAS": 1
    };
    const tagNamesAffectingFontStyle = {
        "I": 1,
        "EM": 1
    };
    const tagNamesAffectingFontWeight = {
        "B": 1,
        "STRONG": 1,
        "H1": 1,
        "H2": 1,
        "H3": 1,
        "H4": 1,
        "H5": 1,
        "H6": 1
    };
    var elementsToConsiderPruning = [];
    var depthInFloat = 0;
    var depthInTable = 0;
    var depthInFontStyle = 0;
    var depthInFontWeight = 0;
    var currentElement = originalArticleNode;
    var view = currentElement.ownerDocument.defaultView;
    var currentCloneElement = clonedArticleNode;
    var articleTitle = this.articleTitle();
    var articleTitleElement = this._articleTitleElement;
    var elementPinToEdge = this.elementPinToEdge(originalArticleNode);
    var clonedElementPinToEdge = null;
    
    function incrementDepthLevels(delta) {
        if (depthInFloat) depthInFloat += delta;
        if (depthInTable) depthInTable += delta;
        if (depthInFontStyle) depthInFontStyle += delta;
        if (depthInFontWeight) depthInFontWeight += delta;
    };
    
    function updateDepthLevelsAfterSiblingTraversal() {
        if (depthInFloat === 1) depthInFloat = 0;
        if (depthInTable === 1) depthInTable = 0;
        if (depthInFontStyle === 1) depthInFontStyle = 0;
        if (depthInFontWeight === 1) depthInFontWeight = 0;
    };
    while (currentElement) {
        var prunedElement = null;
        var tagName = currentCloneElement.tagName;
        currentCloneElement.originalElement = currentElement;
        if (currentElement === elementPinToEdge) clonedElementPinToEdge = currentCloneElement;
        if (tagName in tagNamesToAlwaysPrune) prunedElement = currentCloneElement;
        if (!prunedElement && currentElement === articleTitleElement) prunedElement = currentCloneElement;
        if (!prunedElement && (tagName === "H1" || tagName === "H2")) {
            var distanceFromoriginalArticleNodeTop = currentElement.offsetTop - originalArticleNode.offsetTop;
            if (distanceFromoriginalArticleNodeTop < HeaderMinimumDistanceFromArticleTop) {
                var headerText = innerTextOrTextContent(currentElement);
                var maxDistanceToConsiderSimilar = headerText.length * HeaderLevenshteinDistanceToLengthRatio;
                if (levenshteinDistance(articleTitle, headerText) <= maxDistanceToConsiderSimilar) prunedElement = currentCloneElement;
            }
        }
        var computedStyle;
        if (!prunedElement) computedStyle = getComputedStyle(currentElement);
        if (!prunedElement && tagName === "DIV" && currentCloneElement.parentNode) {
            var elements = currentElement.querySelectorAll("a, blockquote, dl, div, img, ol, p, pre, table, ul");
            var inFloat = depthInFloat || computedStyle["float"] !== "none";
            if (!inFloat && !elements.length) {
                var parentNode = currentCloneElement.parentNode;
                var replacementNode = this.contentDocument.createElement("p");
                while (currentCloneElement.firstChild) {
                    var child = currentCloneElement.firstChild;
                    replacementNode.appendChild(child);
                }
                parentNode.replaceChild(replacementNode, currentCloneElement);
                if (clonedElementPinToEdge === currentCloneElement) clonedElementPinToEdge = replacementNode;
                currentCloneElement = replacementNode;
                currentCloneElement.originalElement = currentElement;
                tagName = currentCloneElement.tagName;
            }
        }
        if (!prunedElement && currentCloneElement.parentNode && tagName in tagNamesToConsiderPruning) elementsToConsiderPruning.push(currentCloneElement);
        if (!prunedElement) {
            if (computedStyle.display === "none") prunedElement = currentCloneElement;
            else if (currentElement !== originalArticleNode && tagName !== "IMG" && !depthInFloat && computedStyle["float"] !== "none" && (cachedElementBoundingRect(currentElement).height >= FloatMinimumHeight || currentElement.childElementCount > 1)) depthInFloat = 1;
        }
        if (!prunedElement) {
            var attributes = currentCloneElement.attributes;
            for (var i = 0; i < attributes.length; i++) {
                var attributeName = attributes[i].nodeName;
                if (AttributesToRemoveRegEx.test(attributeName)) {
                    currentCloneElement.removeAttribute(attributeName);
                    i--;
                }
            }
            if (!depthInFontStyle && computedStyle.fontStyle !== "normal") {
                if (!(tagName in tagNamesAffectingFontStyle)) currentCloneElement.style.fontStyle = computedStyle.fontStyle;
                depthInFontStyle = 1;
            }
            if (!depthInFontWeight && computedStyle.fontWeight !== "normal") {
                if (!(tagName in tagNamesAffectingFontWeight)) currentCloneElement.style.fontWeight = computedStyle.fontWeight;
                depthInFontWeight = 1;
            }
            if (depthInFloat) {
                if (depthInFloat === 1) {
                    if (cachedElementBoundingRect(currentElement).width === cachedElementBoundingRect(originalArticleNode).width) currentCloneElement.setAttribute("class", "float full-width");
                    else currentCloneElement.setAttribute("class", "float " + computedStyle["float"]);
                }
                var widthValue = currentElement.style.getPropertyValue("width");
                if (widthValue) currentCloneElement.style.width = widthValue;
                else {
                    var rules = view.getMatchedCSSRules(currentElement, "", true);
                    if (rules) {
                        for (var i = rules.length - 1; i >= 0; i--) {
                            widthValue = rules[i].style.getPropertyValue("width");
                            if (widthValue) {
                                currentCloneElement.style.width = widthValue;
                                break;
                            }
                        }
                    }
                }
                if (depthInFloat === 1 && !widthValue) currentCloneElement.style.width = cachedElementBoundingRect(currentElement).width + "px";
                var largeElementMargin = currentCloneElement.parentNode === clonedArticleNode ? 36 : 12;
                var clonedWidthValue = currentCloneElement.style.width;
                if (clonedWidthValue && parseInt(clonedWidthValue) >= screen.width - largeElementMargin) currentCloneElement.setAttribute("class", "large-element");
            }
            if (tagName === "TABLE") {
                if (!depthInTable) depthInTable = 1;
            }
            else if (tagName == "VIDEO") {
                var videoBoundingRect = cachedElementBoundingRect(currentElement);
                const largeElementMargin = 36;
                if (videoBoundingRect.width > screen.width - largeElementMargin) {
                    currentCloneElement.setAttribute("class", "large-element");
                }
            }
            else if (tagName === "IMG") {
                currentCloneElement.removeAttribute("border");
                currentCloneElement.removeAttribute("hspace");
                currentCloneElement.removeAttribute("vspace");
                currentCloneElement.removeAttribute("align");
                if (!depthInFloat) {
                    var imageBoundingRect = cachedElementBoundingRect(currentElement);
                    if (imageBoundingRect.width < ImageSizeTiny && imageBoundingRect.height < ImageSizeTiny) currentCloneElement.setAttribute("class", "reader-image-tiny");
                    else if ((imageBoundingRect.width / cachedElementBoundingRect(originalArticleNode).width) > ImageWidthToParentWidthRatio) {
                        currentCloneElement.setAttribute("class", "reader-image-large");
                    }
                } else {
                    currentCloneElement.style.float = computedStyle.float;
                }
            } else if (tagName === "FONT") {
                currentCloneElement.removeAttribute("size");
                currentCloneElement.removeAttribute("face");
                currentCloneElement.removeAttribute("color");
            } else if (tagName === "A" && currentCloneElement.parentNode) {
                var href = currentCloneElement.getAttribute("href");
                if (href && href.length && (href[0] === "#" || href.substring(0, 11) === "javascript:")) {
                    if (!depthInTable && !currentCloneElement.childElementCount && currentCloneElement.parentElement.childElementCount === 1) {
                        var xPathResult = this.contentDocument.evaluate("text()", currentCloneElement.parentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
                        if (!xPathResult.snapshotLength) prunedElement = currentCloneElement;
                    }
                    if (!prunedElement) {
                        var replacementNode = this.contentDocument.createElement("span");
                        if (currentCloneElement.childElementCount === 1 && currentCloneElement.firstElementChild.tagName === "IMG") {
                            var imageElement = currentCloneElement.firstElementChild;
                            if (imageElement.width > AnchorImageMinimumWidth && imageElement.height > AnchorImageMinimumHeight) replacementNode.setAttribute("class", "converted-image-anchor");
                        }
                        if (!replacementNode.className) replacementNode.setAttribute("class", "converted-anchor");
                        while (currentCloneElement.firstChild)
                            replacementNode.appendChild(currentCloneElement.firstChild);
                        currentCloneElement.parentNode.replaceChild(replacementNode, currentCloneElement);
                        currentCloneElement = replacementNode;
                        if (clonedElementPinToEdge === currentCloneElement) clonedElementPinToEdge = replacementNode;
                    }
                }
            }
        }
        var firstElementChild = prunedElement ? null : currentElement.firstElementChild;
        if (firstElementChild) {
            currentElement = firstElementChild;
            currentCloneElement = currentCloneElement.firstElementChild;
            incrementDepthLevels(1);
        } else {
            var nextElementSibling;
            while (currentElement !== originalArticleNode && !(nextElementSibling = currentElement.nextElementSibling)) {
                currentElement = currentElement.parentElement;
                currentCloneElement = currentCloneElement.parentElement;
                incrementDepthLevels(-1);
            }
            if (currentElement === originalArticleNode) {
                if (prunedElement) {
                    if (prunedElement.parentElement) prunedElement.parentElement.removeChild(prunedElement);
                    else if (allowedToReturnNull) return null;
                }
                break;
            }
            currentElement = nextElementSibling;
            currentCloneElement = currentCloneElement.nextElementSibling;
            updateDepthLevelsAfterSiblingTraversal();
        }
        if (prunedElement) {
            if (prunedElement.parentElement) prunedElement.parentElement.removeChild(prunedElement);
            else if (allowedToReturnNull) return null;
        }
    }
    for (var i = elementsToConsiderPruning.length - 1; i >= 0; i--) {
        var element = elementsToConsiderPruning[i];
        if (element.parentNode && this.shouldPruneElement(element, element.originalElement)) {
            if (clonedElementPinToEdge === element) {
                if (!(clonedElementPinToEdge = element.nextElementSibling)) {
                    clonedElementPinToEdge = element.parentElement;
                }
            }
            element.parentNode.removeChild(element);
        }
    }
    var floatElements = this._adoptableArticle.querySelectorAll(".float");
    for (var i = 0; i < floatElements.length; i++) {
        var pruneFloatedElement = false;
        var floatElement = floatElements[i];
        if (!pruneFloatedElement) {
            var anchors = floatElement.querySelectorAll("a, span.converted-image-anchor");
            var replacedAnchors = floatElement.querySelectorAll("span.converted-anchor");
            pruneFloatedElement = floatElement.parentNode && replacedAnchors.length > anchors.length;
        }
        if (!pruneFloatedElement) {
            var plugInsInClonedElement = floatElement.querySelectorAll("embed, object").length;
            var plugInsInOriginalElement = floatElement.originalElement.querySelectorAll("embed, object").length;
            if (!plugInsInClonedElement && plugInsInOriginalElement) pruneFloatedElement = true;
        }
        if (!pruneFloatedElement) {
            var imagesInOriginalElement = floatElement.originalElement.querySelectorAll("img");
            var visibleImagesInOriginalElementCount = 0;
            for (var j = 0; j < imagesInOriginalElement.length; j++) {
                if (isElementVisible(imagesInOriginalElement[j])) visibleImagesInOriginalElementCount++;
                if (visibleImagesInOriginalElementCount > 1) break;
            }
            if (visibleImagesInOriginalElementCount === 1) {
                var imagesInClonedElementCount = floatElement.querySelectorAll("img").length;
                if (!imagesInClonedElementCount) pruneFloatedElement = true;
            }
        }
        if (pruneFloatedElement) {
            if (clonedElementPinToEdge === floatElement) {
                if (!(clonedElementPinToEdge = floatElement.nextElementSibling)) {
                    clonedElementPinToEdge = floatElement.parentElement;
                }
            }
            floatElement.parentNode.removeChild(floatElement);
        }
    }
    if (allowedToReturnNull && !removeWhitespace(clonedArticleNode.innerText).length) return null;
    if (clonedElementPinToEdge != null) {
        var pin = document.createElement("div");
        var nodeRect = clonedElementPinToEdge.originalElement.getBoundingClientRect();
        var offset = nodeRect.height > 0 ? nodeRect.top * 100 / nodeRect.height : 0;
        pin.style.position = "relative";
        pin.style.top = Math.round(-offset) + "%";
        pin.setAttribute("id", "safari-reader-element-marker");
        clonedElementPinToEdge.insertBefore(pin, clonedElementPinToEdge.firstChild);
    }
    return clonedArticleNode;
},
leadingImageNode: function leadingImageNode() {
    const LeadingImageMinimumHeight = 250;
    const LeadingImageMinimumWidthRatio = 0.5;
    const LeadingImageNumberOfAncestorsToSearch = 3;
    var searchScope = this.article.element;
    for (var ancestorCount = 0; ancestorCount < LeadingImageNumberOfAncestorsToSearch; ancestorCount++) {
        if (!searchScope.parentNode) break;
        searchScope = searchScope.parentNode;
        var image = searchScope.getElementsByTagName("img")[0];
        if (image) {
            var imageRect = cachedElementBoundingRect(image);
            if (imageRect.height >= LeadingImageMinimumHeight && imageRect.width >= this._articleWidth * LeadingImageMinimumWidthRatio) {
                var position = this.article.element.compareDocumentPosition(image);
                if (!(position & DocumentPositionPreceding) || (position & DocumentPositionContainedBy)) continue;
                position = this.extraArticle ? this.extraArticle.element.compareDocumentPosition(image) : null;
                if (position && (!(position & DocumentPositionPreceding) || (position & DocumentPositionContainedBy))) continue;
                return image;
            }
        }
    }
    return null;
},
articleTitle: function articleTitle() {
    if (this._articleTitle !== undefined) return this._articleTitle;
    const HeaderMaximumDistance = 500;
    const HeaderMinimumTextLength = 8;
    const HeaderMinimumFontSize = 12;
    const HeaderFontSizeBonusMinimumRatio = 1.1;
    const HeaderFontSizeBonusMultiplier = 1.25;
    const HeaderBonusRegEx = /header|title|headline/i;
    const HeaderRegexBonusMultiplier = 1.5;
    const HeaderContentBonusMultiplier = 1.5;
    const HeaderMaximumDOMDistance = 9;
    const HeaderMinimumFontSizeDifference = 1.5;
    
    function isPrefixOrSuffix(headerText, documentTitle) {
        var position = headerText ? documentTitle.indexOf(headerText) : -1;
        return (position != -1 && (position == 0 || position + headerText.length == documentTitle.length));
    }
    var articleRect = cachedElementBoundingRect(this.articleNode());
    if (this.extraArticleNode() && this.extraArticle.isPrepended) articleRect = cachedElementBoundingRect(this.extraArticleNode());
    var articleCenterX = articleRect.left + (articleRect.width / 2);
    var articleTopY = articleRect.top;
    var articleAdjustedTopY = articleTopY;
    this._articleWidth = articleRect.width;
    this.leadingImage = this.leadingImageNode();
    if (this.leadingImage) {
        var imageRect = cachedElementBoundingRect(this.leadingImage);
        articleAdjustedTopY = imageRect.top;
    }
    var allHeaders = this.contentDocument.querySelectorAll("h1, h2, h3, h4, h5, .headline, .article_title, #hn-headline, .inside-head");
    var bestHeader;
    for (var i = 0; i < allHeaders.length; i++) {
        var header = allHeaders[i];
        var headerRect = cachedElementBoundingRect(header);
        var headerCenterX = headerRect.left + (headerRect.width / 2);
        var headerCenterY = headerRect.top + (headerRect.height / 2);
        var deltaX = headerCenterX - articleCenterX;
        var deltaY = headerCenterY - articleAdjustedTopY;
        var distance = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
        var headerScore = Math.max(HeaderMaximumDistance - distance, 0);
        if (header.className.toLowerCase().indexOf("byline") != -1) continue;
        if (distance > HeaderMaximumDistance) continue;
        if (headerCenterX < articleRect.left || headerCenterX > articleRect.right) continue;
        var headerFontSize = fontSizeFromComputedStyle(getComputedStyle(header));
        if (headerFontSize < HeaderMinimumFontSize) continue;
        var headerText = header.innerText;
        if (isPrefixOrSuffix(headerText, this.contentDocument.title)) headerScore *= HeaderContentBonusMultiplier;
        else if (headerText.length < HeaderMinimumTextLength) continue;
        headerScore *= 1 + TitleCandidateDepthScoreMultiplier * elementDepth(header);
        headerScore *= (headerFontSize / BaseFontSize);
        var fontSize = parseInt(this.contentTextStyle().fontSize);
        if (parseInt(headerFontSize) > fontSize * HeaderFontSizeBonusMinimumRatio) headerScore *= HeaderFontSizeBonusMultiplier;
        if (HeaderBonusRegEx.test(header.className) || HeaderBonusRegEx.test(header.id)) headerScore *= HeaderRegexBonusMultiplier;
        if (!bestHeader || headerScore > bestHeader.headerScore) {
            bestHeader = header;
            bestHeader.headerScore = headerScore;
            bestHeader.headerText = headerText;
        }
    }
    if (bestHeader && domDistance(bestHeader, this.articleNode(), HeaderMaximumDOMDistance + 1) > HeaderMaximumDOMDistance) {
        if (parseInt(getComputedStyle(bestHeader).fontSize) < HeaderMinimumFontSizeDifference * fontSize) bestHeader = null;
    }
    if (bestHeader) {
        this._articleTitle = bestHeader.headerText.trim();
        this._articleTitleElement = bestHeader;
    }
    if (!this._articleTitle) this._articleTitle = this.contentDocument.title;
    return this._articleTitle;
},
articleIsLTR: function articleIsLTR() {
    if (this._articleIsLTR === undefined) {
        var computedStyle = getComputedStyle(this.articleNode());
        this._articleIsLTR = computedStyle ? computedStyle.direction === "ltr" : true;
    }
    return this._articleIsLTR;
},
findSuggestedCandidate: function findSuggestedCandidate() {
    var route = this.suggestedRouteToArticle;
    if (!route || !route.length) return null;
    var node;
    var i;
    for (i = route.length - 1; i >= 0; i--) {
        if (route[i].id) {
            node = this.contentDocument.getElementById(route[i].id);
            if (node) break;
        }
    }
    i++;
    if (!node) node = this.contentDocument;
    while (i < route.length) {
        var step = route[i];
        var child = node.nodeType === Node.DOCUMENT_NODE ? node.documentElement : node.firstElementChild;
        for (var j = 1; child && j < step.index; child = child.nextElementSibling) {
            if (!this.shouldIgnoreInRouteComputation(child)) j++;
        }
        if (!child) return null;
        if (child.tagName !== step.tagName) return null;
        if (step.className && child.className !== step.className) return null;
        node = child;
        i++;
    }
    if (!isElementVisible(node)) return null;
    return new CandidateElement(node, this.contentDocument);
},
findArticleTagCandidateElement: function findArticleTagCandidateElement() {
    var articleTagElements = this.contentDocument.querySelectorAll("article");
    if (articleTagElements.length != 1) return null;
    return CandidateElement.candidateIfElementIsViable(articleTagElements[0], this.contentDocument);
},
canRunReaderDetection: function () {
    var hostname = this.contentDocument.location.hostname;
    var pathname = this.contentDocument.location.pathname;
    for (var hostString in BlacklistedHostsAllowedPathPrefixesMap) {
        var hostRegex = new RegExp(hostString.escapeForRegExp());
        if (!hostRegex.test(hostname)) continue;
        var allowedPathPrefixes = BlacklistedHostsAllowedPathPrefixesMap[hostString];
        for (var i = 0; i < allowedPathPrefixes.length; ++i) {
            var pathPrefix = allowedPathPrefixes[i];
            if (pathname.substring(0, pathPrefix.length) === pathPrefix) return true;
        }
        return false;
    }
    return true;
},
findArticle: function findArticle() {
    if (!this.canRunReaderDetection()) return null;
    var suggestedCandidate = this.findSuggestedCandidate();
    var candidateElements = this.findCandidateElements();
    if (!candidateElements || !candidateElements.length) return suggestedCandidate;
    if (suggestedCandidate && suggestedCandidate.basicScore() >= ReaderMinimumScore) return suggestedCandidate;
    var articleTagElement = this.findArticleTagCandidateElement()
    if (articleTagElement) return articleTagElement;
    var highestScoringElement = this.highestScoringCandidateFromCandidates(candidateElements);
    if (highestScoringElement.element.tagName === "BLOCKQUOTE") {
        var blockquoteParent = highestScoringElement.element.parentNode;
        var numberOfCandidateElements = candidateElements.length;
        for (var i = 0; i < numberOfCandidateElements; i++) {
            var candidateElement = candidateElements[i];
            if (candidateElement.element === blockquoteParent) {
                highestScoringElement = candidateElement;
                break;
            }
        }
    }
    if (suggestedCandidate && highestScoringElement.finalScore() < ReaderMinimumScore) return suggestedCandidate;
    if (highestScoringElement.shouldDisqualifyDueToScoreDensity()) {
        var elements = highestScoringElement.element.querySelectorAll("ul", "li");
        for (var i = 0; i < elements.length; i++) {
            var prohibitedListElementChildren = elements[i].querySelectorAll("a", "div", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "table");
            if (prohibitedListElementChildren.length > 0) continue;
            var textNodes = highestScoringElement.usableTextNodesInElement(elements[i]);
            if (!textNodes.length) continue;
            for (var j = 0; j < textNodes.length; j++)
                highestScoringElement.textNodes.push(textNodes[j]);
        }
        highestScoringElement.rawScore = highestScoringElement.calculateRawScore();
        if (highestScoringElement.shouldDisqualifyDueToScoreDensity()) return null;
    }
    if (highestScoringElement.shouldDisqualifyDueToHorizontalRuleDensity()) return null;
    if (highestScoringElement.shouldDisqualifyDueToHeaderDensity()) return null;
    if (highestScoringElement.shouldDisqualifyDueToSimilarElements(candidateElements)) return null;
    return highestScoringElement;
},
findExtraArticle: function findExtraArticle() {
    if (!this.article) return null;
    for (var i = 0, candidateSearchScope = this.article.element; i < 3 && candidateSearchScope; i++, candidateSearchScope = candidateSearchScope.parentNode) {
        var candidateElements = this.findExtraArticleCandidateElements(candidateSearchScope);
        if (!candidateElements || !candidateElements.length) continue;
        var sortedCandidateElements = this.sortCandidateElementsInDescendingScoreOrder(candidateElements);
        var highestScoringCandidate;
        for (var candidateIndex = 0; candidateIndex < sortedCandidateElements.length; candidateIndex++) {
            highestScoringCandidate = sortedCandidateElements[candidateIndex];
            if (!highestScoringCandidate || !highestScoringCandidate.basicScore()) break;
            if (highestScoringCandidate.shouldDisqualifyDueToScoreDensity()) continue;
            if (highestScoringCandidate.shouldDisqualifyDueToHorizontalRuleDensity()) continue;
            if (highestScoringCandidate.shouldDisqualifyDueToHeaderDensity()) continue;
            if (cachedElementBoundingRect(highestScoringCandidate.element).height < PrependedArticleCandidateMinimumHeight && cachedElementBoundingRect(this.article.element).width != cachedElementBoundingRect(highestScoringCandidate.element).width) continue;
            var textNodeStyle = contentTextStyleForNode(this.contentDocument, highestScoringCandidate.element, true);
            if (!textNodeStyle) continue;
            if (textNodeStyle.fontFamily !== this.contentTextStyle().fontFamily || textNodeStyle.fontSize !== this.contentTextStyle().fontSize) continue;
            if (highestScoringCandidate) return highestScoringCandidate;
        }
    }
    return null;
},
highestScoringCandidateFromCandidates: function highestScoringCandidateFromCandidates(candidateElements) {
    var highestScore = 0;
    var highestScoringElement = null;
    for (var i = 0; i < candidateElements.length; i++) {
        var candidateElement = candidateElements[i];
        var score = candidateElement.basicScore();
        if (score >= highestScore) {
            highestScore = score;
            highestScoringElement = candidateElement;
        }
    }
    return highestScoringElement;
},
sortCandidateElementsInDescendingScoreOrder: function sortCandidateElementsInDescendingScoreOrder(candidateElements) {
    function sortByScore(candidate1, candidate2) {
        if (candidate1.basicScore() != candidate2.basicScore()) return candidate2.basicScore() - candidate1.basicScore();
        return candidate2.depth() - candidate1.depth();
    }
    return candidateElements.sort(sortByScore);
},
findCandidateElements: function findCandidateElements() {
    const MaximumCandidateDetectionTimeInterval = 1000;
    var findCandidateElementsTimeoutDate = Date.now() + MaximumCandidateDetectionTimeInterval;
    var elements = this.contentDocument.getElementsByTagName("*");
    var candidateElements = [];
    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        if (shouldIgnoreElementBySelfOrAncestorTagName(element)) continue;
        var candidate = CandidateElement.candidateIfElementIsViable(element, this.contentDocument);
        if (candidate) candidateElements.push(candidate);
        if (Date.now() > findCandidateElementsTimeoutDate) {
            console.assert(false, "ReaderArticleFinder aborting CandidateElement detection due to timeout");
            candidateElements = [];
            break;
        }
    }
    for (var i = 0; i < candidateElements.length; i++)
        candidateElements[i].element.candidateElement = candidateElements[i];
    for (var i = 0; i < candidateElements.length; i++) {
        var candidateElement = candidateElements[i];
        if (candidateElement.element.tagName !== "BLOCKQUOTE") continue;
        var parentCandidateElement = candidateElement.element.parentElement.candidateElement;
        if (!parentCandidateElement) continue;
        parentCandidateElement.addTextNodesFromCandidateElement(candidateElement);
    }
    for (var i = 0; i < candidateElements.length; i++)
        candidateElements[i].element.candidateElement = null;
    return candidateElements;
},
findExtraArticleCandidateElements: function findExtraArticleCandidateElements(searchScope) {
    if (!this.article) return [];
    if (!searchScope) searchScope = this.article.element;
    var xPathQuery = "preceding-sibling::*/descendant-or-self::*";
    var xPathResults = this.contentDocument.evaluate(xPathQuery, searchScope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    var possibleCandidateCount = xPathResults.snapshotLength;
    var candidateElements = [];
    for (var i = 0; i < possibleCandidateCount; i++) {
        var element = xPathResults.snapshotItem(i);
        if (shouldIgnoreElementBySelfOrAncestorTagName(element)) continue;
        var candidate = CandidateElement.extraArticleCandidateIfElementIsViable(element, this.article, this.contentDocument, true);
        if (candidate) candidateElements.push(candidate);
    }
    xPathQuery = "following-sibling::*/descendant-or-self::*";
    xPathResults = this.contentDocument.evaluate(xPathQuery, searchScope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    possibleCandidateCount = xPathResults.snapshotLength;
    for (var i = 0; i < possibleCandidateCount; i++) {
        var element = xPathResults.snapshotItem(i);
        if (shouldIgnoreElementBySelfOrAncestorTagName(element)) continue;
        var candidate = CandidateElement.extraArticleCandidateIfElementIsViable(element, this.article, this.contentDocument, false);
        if (candidate) candidateElements.push(candidate);
    }
    return candidateElements;
},
isGeneratedBy: function isGeneratedBy(pattern) {
    var generatorMeta = this.contentDocument.head ? this.contentDocument.head.querySelector("meta[name=generator]") : null;
    if (!generatorMeta) return false;
    var generator = generatorMeta.content;
    if (!generator) return false;
    return pattern.test(generator);
},
isMediaWikiPage: function isMediaWikiPage() {
    return this.isGeneratedBy(/^MediaWiki /);
},
isWordPressSite: function isWordPressSite() {
    return this.isGeneratedBy(/^WordPress/);
},
nextPageURLString: function nextPageURLString() {
    if (!this.article) return null;
    if (this.isMediaWikiPage()) return null;
    var bestLink;
    var bestLinkScore = 0;
    var searchScope = this.article.element;
    if (searchScope.parentNode && getComputedStyle(searchScope).display === "inline") searchScope = searchScope.parentNode;
    var possibleSearchScope = searchScope;
    var minimumBottomOffset = cachedElementBoundingRect(searchScope).bottom + LinkMaxVerticalDistanceFromArticle;
    while (isElementNode(possibleSearchScope) && cachedElementBoundingRect(possibleSearchScope).bottom <= minimumBottomOffset)
        possibleSearchScope = possibleSearchScope.parentNode;
    if (possibleSearchScope !== searchScope && (possibleSearchScope === this.contentDocument || isElementNode(possibleSearchScope))) searchScope = possibleSearchScope;
    var anchorElements = this.contentDocument.evaluate(LinkCandidateXPathQuery, searchScope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    var numberOfLinks = anchorElements.snapshotLength;
    if (this.pageNumber <= 2 && !this.prefixWithDateForNextPageURL) {
        var articleURL = this.contentDocument.location.pathname;
        var dateMatch = articleURL.match(LinkDateRegex);
        if (dateMatch) {
            dateMatch = dateMatch[0];
            this.prefixWithDateForNextPageURL = articleURL.substring(0, articleURL.indexOf(dateMatch) + dateMatch.length);
        }
    }
    for (var i = 0; i < numberOfLinks; i++) {
        var link = anchorElements.snapshotItem(i);
        var score = this.scoreNextPageLinkCandidate(link);
        if (score > bestLinkScore) {
            bestLink = link;
            bestLinkScore = score;
        }
    }
    return bestLink ? bestLink.href : null;
},
scoreNextPageLinkCandidate: function scoreNextPageLinkCandidate(link) {
    function isNextOrdinal(referenceString, linkString, linkText, pageNumber) {
        if (linkString.substring(0, referenceString.length) === referenceString) {
            linkString = linkString.substring(referenceString.length);
            referenceString = "";
        }
        var linkOrdinal = linkString.lastInteger();
        if (isNaN(linkOrdinal)) return false;
        var referenceOrdinal = referenceString ? referenceString.lastInteger() : NaN;
        if (isNaN(referenceOrdinal) || referenceOrdinal >= MaximumExactIntegralValue) referenceOrdinal = pageNumber;
        if (linkOrdinal == referenceOrdinal) return linkText.lastInteger() === referenceOrdinal + 1;
        return linkOrdinal === referenceOrdinal + 1;
    }
    
    function parametersFromSearch(search) {
        var map = {};
        var parameters = search.substring(1).split("&");
        for (var i = 0; i < parameters.length; i++) {
            var parameter = parameters[i];
            var equalsIndex = parameter.indexOf("=");
            if (equalsIndex === -1) map[parameter] = null;
            else map[parameter.substring(0, equalsIndex)] = parameter.substring(equalsIndex + 1);
        }
        return map;
    }
    var referenceLocation = this.contentDocument.location;
    if (link.host !== referenceLocation.host) return 0;
    if (link.pathname === referenceLocation.pathname && link.search === referenceLocation.search) return 0;
    if (link.toString().indexOf("#") != -1) return 0;
    if (!isElementVisible(link)) return 0;
    var linkBoundingRect = cachedElementBoundingRect(link);
    var articleBoundingRect = cachedElementBoundingRect(this.article.element);
    var verticalDistanceFromArticle = Math.max(0, Math.max(articleBoundingRect.top - (linkBoundingRect.top + linkBoundingRect.height), linkBoundingRect.top - (articleBoundingRect.top + articleBoundingRect.height)));
    if (linkBoundingRect.top < articleBoundingRect.top) return 0;
    if (verticalDistanceFromArticle > LinkMaxVerticalDistanceFromArticle) return 0;
    var horizontalDistanceFromArticle = Math.max(0, Math.max(articleBoundingRect.left - (linkBoundingRect.left + linkBoundingRect.width), linkBoundingRect.left - (articleBoundingRect.left + articleBoundingRect.width)));
    if (horizontalDistanceFromArticle > 0) return 0;
    var referenceLocationPath = referenceLocation.pathname;
    var linkPath = link.pathname;
    if (this.prefixWithDateForNextPageURL) {
        if (link.pathname.indexOf(this.prefixWithDateForNextPageURL) == -1) return 0;
        referenceLocationPath = referenceLocationPath.substring(this.prefixWithDateForNextPageURL.length);
        linkPath = linkPath.substring(this.prefixWithDateForNextPageURL.length);
    }
    var linkPathComponents = linkPath.substring(1).split("/");
    if (!linkPathComponents[linkPathComponents.length - 1]) linkPathComponents.pop();
    var referencePathComponents = referenceLocationPath.substring(1).split("/");
    var linkEndsWithSlash = false;
    if (!referencePathComponents[referencePathComponents.length - 1]) {
        linkEndsWithSlash = true;
        referencePathComponents.pop();
    }
    if (linkPathComponents.length < referencePathComponents.length) return 0;
    var mismatchCount = 0;
    var nextOrdinalMatchValue = 0;
    var linkText = link.textContent;
    for (var i = 0; i < linkPathComponents.length; i++) {
        var linkComponent = linkPathComponents[i];
        var referenceComponent = i < referencePathComponents.length ? referencePathComponents[i] : "";
        if (referenceComponent !== linkComponent) {
            if (i < referencePathComponents.length - 2) return 0;
            if (linkComponent.length >= referenceComponent.length) {
                var commonSuffixLength = 0;
                while (linkComponent[linkComponent.length - 1 - commonSuffixLength] === referenceComponent[referenceComponent.length - 1 - commonSuffixLength])
                    commonSuffixLength++;
                if (commonSuffixLength) {
                    linkComponent = linkComponent.substring(0, linkComponent.length - commonSuffixLength);
                    referenceComponent = referenceComponent.substring(0, referenceComponent.length - commonSuffixLength);
                }
            }
            if (isNextOrdinal(referenceComponent, linkComponent, linkText, this.pageNumber)) nextOrdinalMatchValue = Math.pow(LinkNextOrdinalValueBase, (i - linkPathComponents.length + 1));
            else mismatchCount++;
        }
        if (mismatchCount > 1) return 0;
    }
    var didEarnURLSemanticBonus = false;
    if (link.search) {
        linkParameters = parametersFromSearch(link.search);
        referenceParameters = parametersFromSearch(referenceLocation.search);
        for (var key in linkParameters) {
            var linkValue = linkParameters[key];
            var referenceValue = key in referenceParameters ? referenceParameters[key] : null;
            if (referenceValue !== linkValue) {
                if (referenceValue === null) referenceValue = "";
                if (linkValue === null) linkValue = "";
                if (linkValue.length < referenceValue.length) mismatchCount++;
                else if (isNextOrdinal(referenceValue, linkValue, linkText, this.pageNumber)) {
                    if (LinkURLSearchParameterKeyMatchRegex.test(key)) {
                        if (referenceLocationPath.toLowerCase() === linkPath.toLowerCase()) {
                            if (this.isWordPressSite() && linkEndsWithSlash) return 0;
                            didEarnURLSemanticBonus = true;
                        } else return 0;
                    } else if (LinkURLBadSearchParameterKeyMatchRegex.test(key)) {
                        mismatchCount++;
                        continue;
                    }
                    nextOrdinalMatchValue = Math.max(nextOrdinalMatchValue, 1 / LinkNextOrdinalValueBase);
                } else mismatchCount++;
            }
        }
    }
    if (!nextOrdinalMatchValue) return 0;
    if (LinkURLPageSlashNumberMatchRegex.test(link.href) || LinkURLSlashDigitEndMatchRegex.test(link.href)) didEarnURLSemanticBonus = true;
    if (!didEarnURLSemanticBonus && linkPathComponents.length == referencePathComponents.length && stringSimilarity(referenceLocationPath, linkPath) < LinkMinimumURLSimilarityRatio) return 0;
    if (LinkURLArchiveSlashDigitEndMatchRegex.test(link)) return 0;
    var score = LinkMatchWeight * (Math.pow(LinkMismatchValueBase, -mismatchCount) + nextOrdinalMatchValue) + LinkVerticalDistanceFromArticleWeight * verticalDistanceFromArticle / LinkMaxVerticalDistanceFromArticle;
    if (didEarnURLSemanticBonus) score += LinkURLSemanticMatchBonus;
    if (link.parentNode.tagName === "LI") score += LinkListItemBonus;
    var linkText = link.innerText;
    if (LinkNextMatchRegEx.test(linkText)) score += LinkNextMatchBonus;
    if (LinkPageMatchRegEx.test(linkText)) score += LinkPageMatchBonus;
    if (LinkContinueMatchRegEx.test(linkText)) score += LinkContinueMatchBonus;
    return score;
},
articleTextContent: function articleTextContent() {
    return this._articleTextContent;
},
readingListItemInformation: function readingListItemInformation() {
    const ReaderTitleMaxLength = 140;
    const ReaderPreviewTextMaxLength = 140;
    var title;
    var previewText;
    if (this.adoptableArticle()) {
        title = this.articleTitle();
        previewText = this.articleTextContent();
    } else {
        title = this.contentDocument.title;
        if (this.contentDocument.body) previewText = this.contentDocument.body.innerText;
    }
    if (!title) title = this.contentDocument.location.href;
    title = title.trim().substring(0, ReaderTitleMaxLength);
    if (!previewText) previewText = "";
    previewText = previewText.trim().substring(0, ReaderPreviewTextMaxLength).replace(/\s+/g, ' ');
    var info = {
        "title": title,
        "previewText": previewText
    };
    return info;
}
}
var ReaderArticleFinderJS = new ReaderArticleFinder(document);